package com.na.game.engine.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.widget.Toast;

import com.na.game.engine.GameActivity;
import com.na.game.engine.GameManager;
import com.na.game.engine.data.DataManager;
import com.na.game.engine.graphics.Graphics;
import com.na.game.engine.graphics.Image;
import com.na.game.engine.graphics.Painter;
import com.na.game.engine.opengl.GLImage;
import com.na.game.engine.widget.Widget;

public class Util {

	public static final Random RND = new Random();
	
	/**
	 * point in the rect
	 * @param x
	 * @param y
	 * @param rect 0-x 1-y 2-width 3-height
	 * @return
	 */
	public static boolean pointInRect(int x, int y, int[] rect) {
		return x >= rect[0] && x <= rect[0] + rect[2] && y >= rect[1] && y <= rect[1] + rect[3];
	}
	
	public static String[] splitStr(String str, String delimiter) {
		List<String> list = new ArrayList<String>();
		int pos = - delimiter.length();
		while (true) {
			int start = pos + delimiter.length();
			pos = str.indexOf(delimiter, start);
			if (pos < 0) {
				String s = str.substring(start);
				list.add(s);
				break;
			}
			String s = str.substring(start, pos);
			list.add(s);
		}
		return list.toArray(new String[list.size()]);
	}
	
	public static int[] parseInts(String[] strs) {
		int[] ints = new int[strs.length];
		for (int i = strs.length - 1; i >= 0; i--) {
			ints[i] = Integer.parseInt(strs[i]);
		}
		return ints;
	}
	
	public static void intersect(Rect src, Rect dst) {
		if (src.left < dst.left) {
			src.left = dst.left;
		}
		if (src.right > dst.right) {
			src.right = dst.right;
		}
		if (src.top < dst.top) {
			src.top = dst.top;
		}
		if (src.bottom > dst.bottom) {
			src.bottom = dst.bottom;
		}
		if (src.isEmpty()) {
			src.left = src.right = src.top = src.bottom = 0;
		}
	}
	
	public static boolean isIntersect(Rect src, Rect dst) {
		return isIntersect(src, dst.left, dst.top, dst.right, dst.bottom);
	}
	
	public static boolean isIntersect(int srcLeft, int srcTop, int srcRight, int srcBottom, Rect dst) {
		return isIntersect(srcLeft, srcTop, srcRight, srcBottom, dst.left, dst.top, dst.right, dst.bottom);
	}
	
	public static boolean isIntersect(Rect src, int dstLeft, int dstTop, int dstRight, int dstBottom) {
		return isIntersect(src.left, src.top, src.right, src.bottom, dstLeft, dstTop, dstRight, dstBottom);
	}
	
	public static boolean isIntersect(int srcLeft, int srcTop, int srcRight, int srcBottom, int dstLeft, int dstTop, int dstRight, int dstBottom) {
		return srcLeft < dstRight && dstLeft < srcRight
				&& srcTop < dstBottom && dstTop < srcBottom;
	}
	
	private static Map<String, Integer> fontSize;
	private static Paint paint;
	private static int measureText(String text, int textSize, boolean isWidth) {
		if (fontSize == null) {
			fontSize = new HashMap<String, Integer>();
		}
		Integer v = fontSize.get(text + "," + textSize + "," + isWidth);
		if (v != null) {
			return v.intValue();
		}
		if (paint == null) {
			paint = new Paint();
			paint.setTypeface(GameManager.get(GameActivity.class).getGameEntity().getDefaultFont());
		}
		if (paint.getTextSize() != textSize) {
			paint.setTextSize(textSize);
		}
		Rect rect = new Rect();
		paint.getTextBounds(text, 0, text.length(), rect);
		int size = isWidth ? rect.width() + 6 : rect.height();
		fontSize.put(text + "," + textSize + "," + isWidth, Integer.valueOf(size));
		return size;
	}
	
	public static int getTextHeight(String text, int textSize) {
		return measureText(text, textSize, false);
	}
	
	public static int getTextWidth(String text, int textSize) {
		return measureText(text, textSize, true);
	}
	
	public static int getTextHeight(String text) {
		return getTextHeight(text, GameConfig.FONT_DEFAULT_SIZE);
	}
	
	public static int getTextWidth(String text) {
		return getTextWidth(text, GameConfig.FONT_DEFAULT_SIZE);
	}
	
	public static int[] getAscendIntsArr(int init, int add, int size) {
		int[] arr = new int[size];
		for (int i = 0; i < size; i++) {
			arr[i] = init;
			init += add;
		}
		return arr;
	}
	
	public static List<Integer> getAscendIntsList(int init, int add, int size) {
		List<Integer> arr = new ArrayList<Integer>(size);
		for (int i = 0; i < size; i++) {
			arr.add(Integer.valueOf(init));
			init += add;
		}
		return arr;
	}
	
	public static InputStream getAssets(String path) {
		return getAssets(null, path);
	}
	
	public static InputStream getAssets(Context context, String path) {
		if (context == null) {
			context = GameManager.get(GameActivity.class);
		}
		InputStream in = null;
		try {
			in = context.getAssets().open(path);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return in;
	}
	
//	public static FileOutputStream openAssetsFileOutputStream(String path) {
//		return openAssetsFileOutputStream(null, path);
//	}
//	
//	public static FileOutputStream openAssetsFileOutputStream(Context context, String path) {
//		if (context == null) {
//			context = GameManager.get(GameActivity.class);
//		}
//		FileOutputStream fos = null;
//		try {
//			fos = context.getAssets().openFd(path).createOutputStream();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		return fos;
//	}
//	
//	public static FileInputStream openAssetsFileInputStream(String path) {
//		return openAssetsFileInputStream(null, path);
//	}
//	
//	public static FileInputStream openAssetsFileInputStream(Context context, String path) {
//		if (context == null) {
//			context = GameManager.get(GameActivity.class);
//		}
//		try {
//			return context.getAssets().openFd(path).createInputStream();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		return null;
//	}
	
	public static FileOutputStream openFileOutputStream(Context context, String path) {
		try {
			return context.openFileOutput(path, Context.MODE_PRIVATE);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static FileInputStream openFileInputStream(Context context, String path) {
		try {
			return context.openFileInput(path);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static File getExternalFile(String path) {
		if (GameConfig.SDCARD == null) {
			return null;
		}
		File file = new File(GameConfig.SDCARD, path);
		if (!file.exists()) {
			try {
				file.getParentFile().mkdirs();
				if (file.createNewFile()) {
					return file;
				}
			} catch (IOException e) {
			}
			return null;
		}
		return file;
	}
	
	public static Document getDoc(String assets) {
		return getDoc(null, assets);
	}
	
	public static Document getDoc(Context context, String assets) {
		Document doc = null;
		try {
			InputStream in = getAssets(context, assets);
			doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in);
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return doc;
	}
	
	public static Document getDoc(File file) {
		try {
			return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static void showToast(String text) {
		showToast(text, Toast.LENGTH_SHORT);
	}
	
	public static void showToast(final String text, final int duration) {
		GameManager.get(GameActivity.class).runOnUiThread(new Runnable() {
			@Override
			public void run() {
				Toast.makeText(GameManager.get(GameActivity.class), text, duration).show();
			}
		});
	}
	
	public static String getDeviceId() {
		return getDeviceId(GameManager.get(GameActivity.class));
	}
	
	private static String deviceId;
	public static String getDeviceId(Context ctx) {
		if (deviceId != null) {
			return deviceId;
		}
		String id = null;
		TelephonyManager tel = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
		if (tel != null) {
			id = tel.getDeviceId();
		}
		if (id == null) {
			WifiManager wifi = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE);
			if (wifi != null) {
				id = wifi.getConnectionInfo().getMacAddress().replaceAll(":", "");
			}
		}
		if (id == null) {
			id = GameManager.get(DataManager.class).get(GameConfig.AUTO_DEVICE_ID, "");
			if (id.length() == 0) {
				id = UUID.randomUUID().toString();
				GameManager.get(DataManager.class).put(GameConfig.AUTO_DEVICE_ID, id);
			}
		}
		deviceId = id;
		return id;
	}
	
	public static String getPhoneInfo() {
		return Build.MANUFACTURER + "," + Build.MODEL + "," + Build.DEVICE + "," + Build.ID + "[" + Build.VERSION.SDK_INT + "-" + Build.VERSION.RELEASE + "]";
	}
	
	public static boolean strEqualsInexact(String src, String... targets) {
		if (src == null || targets == null) {
			return false;
		}
		for (String target : targets) {
			if (target.equals(src)) {
				return true;
			}
		}
		return false;
	}
	
	public static boolean strEqualsExact(String src, String... targets) {
		if (src == null || targets == null) {
			return false;
		}
		for (String target : targets) {
			if (!target.equals(src)) {
				return false;
			}
		}
		return true;
	}
	
	public static String getAppMetaString(Context ctx, String metaName) {
		Bundle meta = getAppMeta(ctx);
		if (meta != null) {
			return meta.getString(metaName);
		}
		return null;
	}
	
	public static boolean getAppMetaBoolean(Context ctx, String metaName) {
		Bundle meta = getAppMeta(ctx);
		if (meta != null) {
			return meta.getBoolean(metaName);
		}
		return false;
	}
	
	public static int getAppMetaInt(Context ctx, String metaName) {
		Bundle meta = getAppMeta(ctx);
		if (meta != null) {
			return meta.getInt(metaName);
		}
		return 0;
	}
	
	private static Bundle getAppMeta(Context ctx) {
		if (ctx == null) {
			ctx = GameManager.get(GameActivity.class);
		}
		try {
			ApplicationInfo info = ctx.getPackageManager().getApplicationInfo(ctx.getPackageName(), PackageManager.GET_META_DATA);
			return info.metaData;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static void destroy() {
		if (fontSize != null) {
			fontSize.clear();
			fontSize = null;
		}
		paint = null;
	}
	
	public static Image wrapImage(Bitmap bitmap) {
		return GameConfig.useOpenGL ? new GLImage(bitmap, "") : new Image(bitmap, "");
	}
	
	public static class DebugPainter implements Painter {
		private Widget w;
		public DebugPainter(Widget widget) {
			w = widget;
		}
		@Override
		public void paint(Graphics g) {
			Rect rect = w.getAbsBound();
			g.setColor(Color.RED);
			g.drawRect(rect.left, rect.top, rect.width() - 1, rect.height() - 1);
		}
	}
	
	public static class NormalBgPainter implements Painter {
		private Widget src;
		private Image image;
		public NormalBgPainter(Widget src) {
			this.src = src;
//			image = GameManager.get(ResourceManager.class).getImageFromAssets(GameConfigEx.RES_BACKGROUND);
		}
		@Override
		public void paint(Graphics g) {
			Rect rect = src.getAbsBound();
			g.setClip(rect.left, rect.top, rect.width(), rect.height());
//			g.drawImage(image, rect.left, rect.top, Layout.TOP_LEFT);
		}
	}
}
